package com.rose.springbootgeneratefile.codegen.mybatis3.model;

import com.rose.springbootgeneratefile.api.CommentGenerator;
import com.rose.springbootgeneratefile.api.FullyQualifiedTable;
import com.rose.springbootgeneratefile.api.IntrospectedColumn;
import com.rose.springbootgeneratefile.api.PropertyRegistry;
import com.rose.springbootgeneratefile.api.dom.java.*;
import com.rose.springbootgeneratefile.codegen.AbstractJavaGenerator;
import com.rose.springbootgeneratefile.codegen.RootClassInfo;
import com.rose.springbootgeneratefile.codegen.mybatis3.elements.AbstractJavaMethodGenerator;
import com.rose.springbootgeneratefile.codegen.mybatis3.elements.MapperMethodGenerator;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static com.rose.springbootgeneratefile.internal.utils.JavaBeansUtil.getJavaBeansField;
import static com.rose.springbootgeneratefile.internal.utils.JavaBeansUtil.getJavaBeansGetter;
import static com.rose.springbootgeneratefile.internal.utils.JavaBeansUtil.getJavaBeansSetter;
import static com.rose.springbootgeneratefile.utils.StringUtility.stringHasValue;

public class BaseRecordGenerator  extends AbstractJavaGenerator {


    @Override
    public List<CompilationUnit> getCompilationUnits() {
        List<CompilationUnit> answer = new ArrayList<CompilationUnit>();
        answer.add(getModelCompilationUnit());
        answer.add(getInterfaceMapperCompilationUnit());
        return answer;
    }


    public CompilationUnit getModelCompilationUnit(){
        FullyQualifiedTable table = introspectedTable.getFullyQualifiedTable();

//        Plugin plugins = context.getPlugins();
        CommentGenerator commentGenerator = context.getCommentGenerator();

        FullyQualifiedJavaType type = new FullyQualifiedJavaType(
                introspectedTable.getBaseRecordType());
        TopLevelClass topLevelClass = new TopLevelClass(type);
        topLevelClass.setVisibility(JavaVisibility.PUBLIC);
        commentGenerator.addJavaFileComment(topLevelClass);

        FullyQualifiedJavaType superClass = getSuperClass();

        if (superClass != null) {
            topLevelClass.setSuperClass(superClass);
            topLevelClass.addImportedType(superClass);
        }
        commentGenerator.addModelClassComment(topLevelClass, introspectedTable);

        List<IntrospectedColumn> introspectedColumns = getColumnsInThisClass();

        if (introspectedTable.isConstructorBased()) {
            addParameterizedConstructor(topLevelClass);

            if (!introspectedTable.isImmutable()) {
                addDefaultConstructor(topLevelClass);
            }
        }

        String rootClass = getRootClass();
        for (IntrospectedColumn introspectedColumn : introspectedColumns) {
            if (RootClassInfo.getInstance(rootClass, null)
                    .containsProperty(introspectedColumn)) {
                continue;
            }

            Field field = getJavaBeansField(introspectedColumn, context, introspectedTable);
//            if (plugins.modelFieldGenerated(field, topLevelClass,
//                    introspectedColumn, introspectedTable,
//                    Plugin.ModelClassType.BASE_RECORD)) {
            topLevelClass.addField(field);
            topLevelClass.addImportedType(field.getType());
//            }

            Method method = getJavaBeansGetter(introspectedColumn, context, introspectedTable);
//            if (plugins.modelGetterMethodGenerated(method, topLevelClass,
//                    introspectedColumn, introspectedTable,
//                    Plugin.ModelClassType.BASE_RECORD)) {
            topLevelClass.addMethod(method);
//            }

            if (!introspectedTable.isImmutable()) {
                method = getJavaBeansSetter(introspectedColumn, context, introspectedTable);
//                if (plugins.modelSetterMethodGenerated(method, topLevelClass,
//                        introspectedColumn, introspectedTable,
//                        Plugin.ModelClassType.BASE_RECORD)) {
                topLevelClass.addMethod(method);
//                }
            }
        }
        return topLevelClass;
    }


    public CompilationUnit getInterfaceServiceCompilationUnit(){


        CommentGenerator commentGenerator = context.getCommentGenerator();

        FullyQualifiedJavaType type = new FullyQualifiedJavaType(introspectedTable.getBaseRecordType()+"Service");
        Interface interfaze = new Interface(type);
        interfaze.setVisibility(JavaVisibility.PUBLIC);
        commentGenerator.addJavaFileComment(interfaze);

        String rootInterface = introspectedTable
                .getTableConfigurationProperty(PropertyRegistry.ANY_ROOT_INTERFACE);
//        if (!stringHasValue(rootInterface)) {
//            rootInterface = context.getJavaClientGeneratorConfiguration()
//                    .getProperty(PropertyRegistry.ANY_ROOT_INTERFACE);
//        }

        if (stringHasValue(rootInterface)) {
            FullyQualifiedJavaType fqjt = new FullyQualifiedJavaType(
                    rootInterface);
            interfaze.addSuperInterface(fqjt);
            interfaze.addImportedType(fqjt);
        }
        List<String> methods = Arrays.asList("insert");
        AbstractJavaMethodGenerator methodGenerator = new MapperMethodGenerator(context,introspectedTable);
        for (String method:methods){
            addMethod(interfaze,method,methodGenerator);
        }
//        addCountByExampleMethod(interfaze);
//        addDeleteByExampleMethod(interfaze);
//        addDeleteByPrimaryKeyMethod(interfaze);
//        addInsertMethod(interfaze);
//        addInsertSelectiveMethod(interfaze);
//        addSelectByExampleWithBLOBsMethod(interfaze);
//        addSelectByExampleWithoutBLOBsMethod(interfaze);
//        addSelectByPrimaryKeyMethod(interfaze);
//        addUpdateByExampleSelectiveMethod(interfaze);
//        addUpdateByExampleWithBLOBsMethod(interfaze);
//        addUpdateByExampleWithoutBLOBsMethod(interfaze);
//        addUpdateByPrimaryKeySelectiveMethod(interfaze);
//        addUpdateByPrimaryKeyWithBLOBsMethod(interfaze);
//        addUpdateByPrimaryKeyWithoutBLOBsMethod(interfaze);


        return interfaze;

    }


    public CompilationUnit getInterfaceMapperCompilationUnit() {

        CommentGenerator commentGenerator = context.getCommentGenerator();

        FullyQualifiedJavaType type = new FullyQualifiedJavaType(introspectedTable.getBaseRecordType()+"Mapper");
        Interface interfaze = new Interface(type);
        interfaze.setVisibility(JavaVisibility.PUBLIC);
        commentGenerator.addJavaFileComment(interfaze);

        String rootInterface = introspectedTable
                .getTableConfigurationProperty(PropertyRegistry.ANY_ROOT_INTERFACE);
//        if (!stringHasValue(rootInterface)) {
//            rootInterface = context.getJavaClientGeneratorConfiguration()
//                    .getProperty(PropertyRegistry.ANY_ROOT_INTERFACE);
//        }

        if (stringHasValue(rootInterface)) {
            FullyQualifiedJavaType fqjt = new FullyQualifiedJavaType(
                    rootInterface);
            interfaze.addSuperInterface(fqjt);
            interfaze.addImportedType(fqjt);
        }
        List<String> methods = Arrays.asList("insert");
        AbstractJavaMethodGenerator methodGenerator = new MapperMethodGenerator(context,introspectedTable);
        for (String method:methods){
            addMethod(interfaze,method,methodGenerator);
        }
//        addCountByExampleMethod(interfaze);
//        addDeleteByExampleMethod(interfaze);
//        addDeleteByPrimaryKeyMethod(interfaze);
//        addInsertMethod(interfaze);
//        addInsertSelectiveMethod(interfaze);
//        addSelectByExampleWithBLOBsMethod(interfaze);
//        addSelectByExampleWithoutBLOBsMethod(interfaze);
//        addSelectByPrimaryKeyMethod(interfaze);
//        addUpdateByExampleSelectiveMethod(interfaze);
//        addUpdateByExampleWithBLOBsMethod(interfaze);
//        addUpdateByExampleWithoutBLOBsMethod(interfaze);
//        addUpdateByPrimaryKeySelectiveMethod(interfaze);
//        addUpdateByPrimaryKeyWithBLOBsMethod(interfaze);
//        addUpdateByPrimaryKeyWithoutBLOBsMethod(interfaze);


        return interfaze;
    }

    private void addMethod(Interface interfaze, String method, AbstractJavaMethodGenerator methodGenerator) {
        try {
            Class<? extends AbstractJavaMethodGenerator> aClass = methodGenerator.getClass();
            java.lang.reflect.Method m = aClass.getDeclaredMethod(method,Interface.class);
            m.invoke(methodGenerator,interfaze);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public List<CompilationUnit> getExtraCompilationUnits() {
        return null;
    }
    /**
     * 获取父类
     * @return
     */
    private FullyQualifiedJavaType getSuperClass() {
        FullyQualifiedJavaType superClass;
//        if (introspectedTable.getRules().generatePrimaryKeyClass()) {
//            superClass = new FullyQualifiedJavaType(introspectedTable
//                    .getPrimaryKeyType());
//        } else {
            String rootClass = getRootClass();
            if (rootClass != null) {
                superClass = new FullyQualifiedJavaType(rootClass);
            } else {
                superClass = null;
            }
//        }

        return superClass;
    }

    /**
     *  获取这个类中所有的列
     * @return
     */
    private List<IntrospectedColumn> getColumnsInThisClass() {
        List<IntrospectedColumn> introspectedColumns;
//        if (includePrimaryKeyColumns()) {
//            if (includeBLOBColumns()) {
//                introspectedColumns = introspectedTable.getAllColumns();
//            } else {
//                introspectedColumns = introspectedTable.getNonBLOBColumns();
//            }
//        } else {
//            if (includeBLOBColumns()) {
//                introspectedColumns = introspectedTable
//                        .getNonPrimaryKeyColumns();
//            } else {
                introspectedColumns = introspectedTable.getBaseColumns();
//            }
//        }

        return introspectedColumns;
    }

    /**
     * 设置有参的构造函数
     * @param topLevelClass
     */
    private void addParameterizedConstructor(TopLevelClass topLevelClass) {
        Method method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setConstructor(true);
        method.setName(topLevelClass.getType().getShortName());
        context.getCommentGenerator().addGeneralMethodComment(method, introspectedTable);

        List<IntrospectedColumn> constructorColumns = introspectedTable.getAllColumns();

        for (IntrospectedColumn introspectedColumn : constructorColumns) {
            method.addParameter(new Parameter(introspectedColumn.getFullyQualifiedJavaType(),
                    introspectedColumn.getJavaProperty()));
            topLevelClass.addImportedType(introspectedColumn.getFullyQualifiedJavaType());
        }

        StringBuilder sb = new StringBuilder();
//        if (introspectedTable.getRules().generatePrimaryKeyClass()) {
//            boolean comma = false;
//            sb.append("super("); //$NON-NLS-1$
//            for (IntrospectedColumn introspectedColumn : introspectedTable
//                    .getPrimaryKeyColumns()) {
//                if (comma) {
//                    sb.append(", "); //$NON-NLS-1$
//                } else {
//                    comma = true;
//                }
//                sb.append(introspectedColumn.getJavaProperty());
//            }
//            sb.append(");"); //$NON-NLS-1$
//            method.addBodyLine(sb.toString());
//        }

        List<IntrospectedColumn> introspectedColumns = getColumnsInThisClass();

        for (IntrospectedColumn introspectedColumn : introspectedColumns) {
            sb.setLength(0);
            sb.append("this."); //$NON-NLS-1$
            sb.append(introspectedColumn.getJavaProperty());
            sb.append(" = "); //$NON-NLS-1$
            sb.append(introspectedColumn.getJavaProperty());
            sb.append(';');
            method.addBodyLine(sb.toString());
        }

        topLevelClass.addMethod(method);
    }


}
